package com.legendframework.core.dao.ioc;

import com.legendframework.core.Store;
import com.legendframework.core.aop.AbstractProxy;
import com.legendframework.core.aop.LegendCglibProxy;
import com.legendframework.core.aop.TargetClassAware;
import com.legendframework.core.ioc.CommonBeansGenerate;
import com.legendframework.core.dao.annotation.EntityDao;
import com.legendframework.core.ioc.exception.BeansException;
import com.legendframework.core.AbstractLegendPlugin;
import com.legendframework.core.dao.DataResources;
import com.legendframework.core.dao.EntityDaoGenerate;
import com.legendframework.core.dao.IDao;
import com.legendframework.core.dao.Return;
import com.legendframework.core.dao.support.ClassUtils;
import com.legendframework.core.support.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

/**
 * @see EntityDao 方式的Bean注入类型
 */
public class EntityDaoBeansGenerate extends CommonBeansGenerate {

    public EntityDaoBeansGenerate(Store store) {
        super(store);
    }

    @Override
    public String getBeanName(Class<?> cls) {
        return StringUtils.isEmpty(cls.getAnnotation(EntityDao.class).value()) ? cls.getName() : cls.getAnnotation(EntityDao.class).value();
    }

    @Override
    public Class<? extends Annotation> getAnnotation() {
        return EntityDao.class;
    }

    @Override
    protected Return<String, Object> newInstance(Class cls , AbstractLegendPlugin plugin) {
        try {
            if (!IDao.class.isAssignableFrom(cls)) {
                throw new BeansException("这个类: '"+cls.getName()+"'需要是: '"+ IDao.class.getName()+"' 的子类");
            }
            //获取Bean名称
            String beanName = getBeanName(cls);

            String configDirectoryName = plugin.getSaveFileName().getConfigDirectoryName();
            if (StringUtils.isEmpty(configDirectoryName)) {
                configDirectoryName = plugin.getName();
            }
            //实例化
            DataResources config = new DataResources();
            config.setDataType(store.getDataResources().getDataType());
            config.setDataSource(store.getDataResources().getDataSource());
            config.setYamlParentPath(store.getDataResources().getYamlParentPath().endsWith(configDirectoryName) ? store.getDataResources().getYamlParentPath() : store.getDataResources().getYamlParentPath() +"/"+configDirectoryName);
            return Return.build(beanName,getAop(cls).apply(injectionBean(beanName,EntityDaoGenerate.getDaoByDaoType(cls, config,store.getJdbcTransaction(),store.getYamlTransaction()),plugin)));
        } catch (Throwable e) {
            throw new BeansException("构建Bean: ["+cls.getName()+"] 失败, 原因：'"+ e.getMessage()+"'",e);
        }

    }

    @Override
    protected AbstractProxy getProxyAop() {
        return null;
    }

    private Function getAop(Class cls){
        return new AbstractProxy() {
            @Override
            public Object apply(Object t) {
                //对jdk动态代理进行增强
                List<Class<?>> classes = new ArrayList<>(Arrays.asList(ClassUtils.getAllInterface(t.getClass())));
                classes.add(TargetClassAware.class);
                classes.add(cls);
                return LegendCglibProxy.newProxyInstance(this.getClass().getClassLoader(),
                        t.getClass(),
                        classes.toArray(new Class[0]),
                        getInvocationHandler(t));
            }

            @Override
            public void enhance(Object source, Method method, Object[] args) {

            }

            @Override
            public Object postposition(Object source, Method method, Object[] args, Object result) {
                return result;
            }

            @Override
            public Object exceptionHandle(Object source, Method method, Object[] args, Throwable e) throws Throwable {
                throw e;
            }
        };
    }
}
